home *** CD-ROM | disk | FTP | other *** search
- /**************************************************************************
-
- *** Powerpacker Patcher ***
-
- Version 1.4
-
- PP is a small utility which enables programs to get at Powerpacked
- datafiles in a completely transparent fashion. Any program attempting to
- open a Powerpacked datafile will receive the "uncrunched" version of that
- file.
-
- This is acomplished by patching some vital DOS functions, thus
- redirecting calls to these to my own internal routines. The overall effect
- is that Powerpacked datafiles appear as normal files. You can TYPE them in
- a CLI window, or bring them directly into your favourite editor. Another
- good way to use this proggy is if you crunch your workbench icons.
- Workbench will never know the difference, but it reduces the diskspace
- occupied by icons by some 65-70% (usually).
-
- Of course, there is a nominal performance reduction in the DOS, which
- is caused by the decruncher, but this doesn't seem too annoying.
- Especially not if you use optimized (B.A.D.) disks, or increase the size of
- the diskbuffers (using the CLI command 'Addbuffers' or equivalent).
-
- For [much] further info, read the DOC file.
-
- Compiles under Aztec V5.0b using large code/large data/32 bit integers.
- Should do fine under Lattice, too, if you fix the #pragma's.
-
- Shareware 1991, Copyright (C) 1991 by Michael Berg
- Sct. Peders Gade 24A, 2th
- 8900 Randers
- DENMARK
-
- **************************************************************************/
-
- /* That's right -- ALL of these are necessary! */
- #include <pragmas.h>
- #include <exec/execbase.h>
- #include <exec/nodes.h>
- #include <exec/lists.h>
- #include <exec/memory.h>
- #include <libraries/dos.h>
- #include <libraries/dosextens.h>
- #include <workbench/startup.h>
- #include <workbench/workbench.h>
-
- /* Well, the compiler has the inline-code ability -- why not use it? */
- #define strlen _BUILTIN_strlen
- #define strcpy _BUILTIN_strcpy
-
- /* loop construct */
- #define FOREVER for(;;)
-
- /* Externals */
- extern int myPPLoadData(BPTR,UBYTE **,int *);
- extern struct Task *res(char *,int,int (*fptr)(),int);
- extern struct MsgPort *myCreatePort(char *,int);
- extern void myDeletePort(struct MsgPort *);
- extern int addfilenode(BPTR,char *,BPTR);
- extern struct filenode *findfilenode(BPTR);
- extern void calcsize(char *,short *,short *,short *,short *);
- extern char *stoa(short,char *);
- extern struct WBStartup *WBenchMsg;
-
- /* Open()-patch related functions */
- extern void MakeOpen(void), RestOpen(void);
- extern BPTR RealOpen(char *, int);
- extern BPTR NewOpen(char *, int);
- #pragma regcall(RealOpen(d1,d2)) /* All of these PRAGMAs are EXTREMELY */
- #pragma regcall(NewOpen(d1,d2)) /* important !!!!!!!!!! */
-
- /* Close()-patch related functions */
- extern void MakeClose(void), RestClose(void);
- extern void RealClose(BPTR);
- extern void NewClose(BPTR);
- #pragma regcall(RealClose(d1))
- #pragma regcall(NewClose(d1))
-
- /* Examine()-patch related functions */
- extern void MakeExamine(void), RestExamine(void);
- extern int RealExamine(BPTR, struct FileInfoBlock *);
- extern int NewExamine(BPTR, struct FileInfoBlock *);
- #pragma regcall(RealExamine(d1,d2))
- #pragma regcall(NewExamine(d1,d2))
-
- /* Write()-patch related functions */
- extern void MakeWrite(void), RestWrite(void);
- extern int RealWrite(BPTR, char *, int);
- extern int NewWrite(BPTR, char *, int);
- #pragma regcall(RealWrite(d1,d2,d3))
- #pragma regcall(NewWrite(d1,d2,d3))
-
- /* Define the maximum length of a filename and its path.
- ** 256 is, as far as I can tell, the AmigaDOS (BSTR) limit
- */
- #define MAXPATHLEN 256
-
- /* Match tag for PowerPacked files (not encrypted) */
- #define PP20 (('P' << 24) + ('P' << 16) + ('2' << 8) + '0')
-
- /* One of these for each opened, powerpacked file, which has not yet been
- ** closed by the Open()'er.
- */
- struct filenode
- {
- struct MinNode mn;
-
- BPTR filehandle; /* Our new file */
- char *new_filename;
- BPTR orig_file;
- short dirty;
- };
-
- /* For inter-process communication */
- typedef struct
- {
- struct Message Msg;
- int Result;
- /* Additional parameters will live here, eventually */
- } MYMSG;
-
- /* Global data */
- struct MinList templist;
- struct Window *win;
- struct IntuitionBase *IntuitionBase;
- struct IconBase *IconBase;
- int patched, wbmode;
-
- USHORT opencnt,closecnt,examcnt,writecnt;
- USHORT pending_exit;
-
- char temppath[MAXPATHLEN];
- short vcheck;
-
- struct MsgPort *pp_port;
- char *pp_portname = "pp_port";
-
- /* Misc */
- char *gbanner = " Powerpacker Patcher V1.4\n\
- Copyright © 1991, Michael Berg\n Installation completed\n";
-
- char *offbanner = " Powerpacker Patcher V1.4\n\
- Copyright © 1991, Michael Berg\n Removal completed\n";
-
- char *wbbanner =
- " Installation trouble?\n\n\
- Simply double-click on my icon, or do an\n\
- extended selection on a disk or drawer\n\
- icon (tells me where to put temporary\n\
- files). Your AmigaDOS manual will tell\n\
- you how to do extended selections.\n";
-
- char *clibanner =
- "Syntax: PP [-n] [-c] [<temppath>] ( -c and RAM: are defaults)\n";
-
- char *wbopts =
- "My icon contains some TOOLTYPE values that\n\I can't make any sense \
- of. Select INFO from\nthe Workbench menu to fix this.\n";
-
- char *virmsg1 =
- " *** WARNING ***\n\n The DOS vector for ";
-
- char *virmsg2 =
- "() has been changed by someone!\n Your machine may be subject \
- to a link-virus attack!\n\n I can no longer guarantee \
- any kind of DOS integrity and\n protection against virus \
- attacks. This is a one-time\n message, from now on you're \
- on your own...\n\n Note: A changed vector doesn't have \
- to imply a virus\n attack. It is most likely a harmless program \
- which is merely\n trying to install itself. I suggest you consult \
- your virus\n checker as soon as possible. Just to be sure.\n\n\
- Press RETURN -> ";
-
- char *defpath = "RAM:";
-
- void wbmsg(register char *what)
- {
- register BPTR fh;
- short l,t,w,h;
- char conspec[40];
- char *tmp;
-
- calcsize(what,&l,&t,&w,&h);
- strcpy(conspec,"CON:");
- tmp = stoa(l,conspec+4);
- *tmp++ = '/';
- tmp = stoa(t,tmp);
- *tmp++ = '/';
- tmp = stoa(w,tmp);
- *tmp++ = '/';
- strcpy(stoa(h,tmp),"/Message From PP");
-
- if (fh = Open(conspec,MODE_NEWFILE))
- {
- if (IntuitionBase) WBenchToFront();
- Write(fh,what,strlen(what));
- Delay((3*strlen(what))/2); /* Weird, but works okay */
- Close(fh);
- }
- }
-
- /* Small puts() function (doesn't do a newline, though). If running from
- ** CLI, print the message in the CLI window. If running from WB, show the
- ** message in a small console window.
- */
- void Say(register char *what)
- {
- if (wbmode)
- wbmsg(what);
- else
- {
- register BPTR out = Output();
-
- /* Do we still have stdout? (CLI may have been closed..) */
- if (out)
- Write(out,what,strlen(what));
- else
- wbmsg(what);
- }
- }
-
- void viruswarn(register char *vect)
- {
- static short firstmsg = 1;
-
- /* This is an important message. Even if we are running as a CLI
- ** child, we must open a window for the message to appear in
- */
-
- if (firstmsg && vcheck)
- {
- register BPTR fh;
- char dummy;
-
- firstmsg = 0;
-
- if (fh = RealOpen("CON:72/22/520/148/IMPORTANT MESSAGE FROM PP",MODE_NEWFILE))
- {
- WBenchToFront();
- RealWrite(fh,virmsg1,strlen(virmsg1));
- RealWrite(fh,vect,strlen(vect));
- RealWrite(fh,virmsg2,strlen(virmsg2));
- Read(fh,&dummy,1);
- RealClose(fh);
- }
- }
- }
-
- void cleanup()
- {
- if (IntuitionBase) CloseLibrary(IntuitionBase);
-
- /* Get rid of our port */
- if (pp_port)
- myDeletePort(pp_port);
-
- /* We have to go to sleep until there are no more tasks executing
- ** our code
- */
- while (opencnt+closecnt+examcnt+writecnt)
- Delay(50);
-
- /* Restore the original DOS functions. You will not find these
- ** functions in the sourcecode. They are generated by the assembler
- ** macro DOSLibPatch -- see asmsup.c
- */
- if (patched)
- {
- Forbid();
- RestOpen();
- RestClose();
- RestExamine();
- RestWrite();
- Permit();
- }
- }
-
- /* Universal termination code */
- void die(int doscode,char *errmsg)
- {
- /* Print the (optional) error message */
- if (errmsg)
- Say(errmsg);
-
- cleanup();
-
- /* Finally! */
- exit(doscode);
- }
-
- /* Install the DOS patches */
- void installpatch()
- {
- Forbid();
- MakeOpen();
- MakeClose();
- MakeExamine();
- MakeWrite();
- Permit();
-
- patched = 1;
- }
-
- /* initialize lists */
- void initlist()
- {
- NewList((struct List *)&templist);
- }
-
- void doport()
- {
- if (!(pp_port = myCreatePort(pp_portname,0)))
- die(30,"Couldn't create a message port\n");
- }
-
- /* passargs passes messages to the 'PP' already running somewhere */
- void passargs(register ac, register char **av)
- {
- MYMSG m;
- register struct Process *myself;
-
- myself = (struct Process *)FindTask(0);
-
- m.Msg.mn_Node.ln_Type = NT_MESSAGE;
- m.Msg.mn_Length = sizeof(MYMSG);
- m.Msg.mn_ReplyPort = &myself->pr_MsgPort;
-
- /* Passing of future parameters go here */
-
- /* Tell him the bad news */
- PutMsg(pp_port,(struct Message *)&m);
- WaitPort(&myself->pr_MsgPort);
- GetMsg(&myself->pr_MsgPort);
-
- if (m.Result)
- Say(offbanner);
- else
- Say("Can't remove PP just yet. Try again a little later!\n");
- }
-
- void finalizepath()
- {
- register char c;
-
- c = temppath[strlen(temppath)-1];
- if (c != ':' && c != '/')
- strcat(temppath,"/");
- }
-
- void badstartup()
- {
- die(10,wbmode? wbbanner : clibanner);
- }
-
- void checkokpath()
- {
- register BPTR lock;
- register char *c;
- register allok = 0;
- char testdir[MAXPATHLEN];
-
- strcpy(testdir,temppath);
- c = testdir + strlen(testdir) - 1;
- if (*c == '/') *c = '\0';
-
- if (lock = Lock(testdir,ACCESS_READ))
- {
- register struct FileInfoBlock *fib;
-
- if (fib = AllocMem(sizeof(*fib),MEMF_CLEAR))
- {
- if (Examine(lock,fib))
- allok = (fib->fib_DirEntryType >= 0);
-
- FreeMem(fib,sizeof(*fib));
- }
- UnLock(lock);
- }
-
- if (!allok)
- die(10,"Could not validate your path selection\n");
- }
-
- void buildfromlock(register BPTR lock, register char *name)
- {
- register struct FileInfoBlock *fib;
- register BPTR olddir,newlock;
- char *fullname();
-
- olddir = CurrentDir(lock);
-
- if (!(newlock = Lock(name,ACCESS_READ)))
- {
- CurrentDir(olddir);
- die(10,"Could not get a lock on your specified path\n");
- }
-
- if (fib = AllocMem(sizeof(*fib),MEMF_CLEAR))
- {
- register retval;
-
- if (retval = Examine(newlock,fib))
- strcpy(temppath,fullname(newlock,fib));
-
- UnLock(newlock);
- CurrentDir(olddir);
- FreeMem(fib,sizeof(*fib));
-
- if (!retval)
- die(10,"Cannot examine your path specification\n");
- }
- else
- {
- UnLock(newlock);
- die(30,"Running low on memory!\n");
- }
- }
-
- badopts()
- {
- if (wbmode)
- die(30,wbopts);
- else
- die(30,clibanner);
- }
-
- handlecliopts(register ac, register char **av)
- {
- register short f=0;
- register char *tmp;
-
- /* Default flags */
- vcheck = 1; /* Check for changing vectors */
-
- for (++av, --ac; ac; ac--, av++)
- {
- if (**av == '-')
- {
- while (*(++*av))
- {
- switch(**av)
- {
- case 'n' : case 'N' :
- vcheck = 0;
- continue;
-
- case 'c' : case 'C' :
- vcheck = 1;
- continue;
-
- default :
- return(0);
- }
- }
- }
- else
- {
- switch (f++)
- {
- case 0 :
- strcpy(temppath,*av);
- break;
- default:
- return(0);
- }
- }
- }
-
- if (!f)
- strcpy(temppath,defpath);
-
- return(1);
- }
-
- parseopt(char *opt)
- {
- /* The stricmp() function is my own. See 'misc.c' */
-
- if (stricmp(opt,"NOCHECK"))
- vcheck = 0;
- else if (stricmp(opt,"CHECK"))
- vcheck = 1;
- else
- return(0);
-
- return(1);
- }
-
- handlewbopts()
- {
- struct WBArg *arg = WBenchMsg->sm_ArgList;
- int rv = 0;
-
- if (!(IconBase = OpenLibrary("icon.library",0)))
- die(30,"Can't open the 'icon.library' (?!)\n");
-
- if (arg->wa_Lock && *arg->wa_Name)
- {
- char **tooltypes;
- struct DiskObject *myicon;
-
- if (myicon = GetDiskObject(arg->wa_Name))
- {
- for (tooltypes=myicon->do_ToolTypes; *tooltypes; tooltypes++)
- rv = parseopt(*tooltypes);
- FreeDiskObject(myicon);
- }
- }
-
- CloseLibrary(IconBase);
-
- return(rv);
- }
-
- /* Executed when PP starts up the very first time */
- void doinitargs(register ac, register char **av)
- {
- register char c;
- register struct WBArg *arg;
-
- /* So far, the only thing you can tell PP is where to put all
- ** the temporary files. This defaults to RAM: when no argument
- ** is given. Workbench argument passing is fully supported.
- */
- if (!ac)
- {
- if (!handlewbopts())
- badopts();
-
- switch (WBenchMsg->sm_NumArgs)
- {
- case 1 : strcpy(temppath,defpath);
- break;
-
- case 2 : arg = &WBenchMsg->sm_ArgList[1];
- if (arg->wa_Lock)
- buildfromlock(arg->wa_Lock,arg->wa_Name);
- else
- /* Should never happen */
- strcpy(temppath,arg->wa_Name);
- break;
-
- default: badstartup();
- }
- }
- else
- if (!handlecliopts(ac,av))
- badopts();
-
- finalizepath();
- checkokpath();
- }
-
- void openlibs()
- {
- if (!(IntuitionBase = OpenLibrary("intuition.library",0)))
- die(30,"Missing 'intuition.library'\n");
- }
-
- /* Open up everything */
- void openstuff(register ac, register char **av)
- {
- openlibs();
-
- if (pp_port = FindPort(pp_portname))
- {
- /* There's already a working copy of PP running somewhere.
- ** Pass the arguments along to it, and then exit.
- */
- passargs(ac,av);
-
- /* Don't let die() remove the port */
- pp_port = NULL;
- die(0,NULL);
- }
-
- /* This is the first time around. Install everything */
- doinitargs(ac,av);
-
- initlist();
- installpatch();
- doport();
- }
-
- /* This baby builds a complete filename (including a path) from a BCPL
- ** pointer to a filehandle. Optimizations are most welcome. All those
- ** ParentDir() calls take a LONG time.
- */
- char *fullname(register BPTR lock, register struct FileInfoBlock *fib)
- {
- static char pathandfile[MAXPATHLEN];
- char tmp[MAXPATHLEN];
- register BPTR parentlock, unlocklock;
- register char *co;
-
- strcpy(pathandfile,fib->fib_FileName);
-
- parentlock = lock;
- unlocklock = (BPTR)0;
-
- while (parentlock = ParentDir(parentlock))
- {
- if (unlocklock)
- UnLock(unlocklock);
-
- if (patched? RealExamine(parentlock,fib) : Examine(parentlock,fib))
- {
- strcpy(tmp,fib->fib_FileName);
- strcat(tmp,"/");
- strcat(tmp,pathandfile);
- strcpy(pathandfile,tmp);
- }
- else
- {
- UnLock(parentlock);
- return(NULL);
- }
-
- unlocklock = parentlock;
- }
-
- if (unlocklock)
- {
- UnLock(unlocklock);
-
- if (co = (char *)index(pathandfile,'/'))
- *co = ':';
- }
- else
- strcat(pathandfile,":");
-
- /* This fixes a bug in the old RAM disk */
- if (!strcmp(pathandfile,":"))
- strcpy(pathandfile,"RAM:");
-
- return(pathandfile);
- }
-
- reallyfile(register BPTR handle)
- {
- return (!IsInteractive(handle));
- }
-
- /* When somebody opens a PP file, we decrunch it into a temporary file
- ** and return a filehandle to that file. When the caller closes the file
- ** (which he thinks is the original disk file), he will really be closing
- ** the temporary file. This is a good chance for us to get rid of it,
- ** so that the temporary directory won't get crowded in time. HOWEVER!
- ** If the caller has written new data into the file, we have to rewrite the
- ** temporary file over the original (disk) file. flushout() does exactly
- ** that.
- */
- void flushout(register struct filenode *fn)
- {
- register BPTR orighandle;
- char buffer[2048]; /* Should suffice */
- register short readlen;
-
- Seek(fn->filehandle, 0, -1); /* Our file */
- Seek(fn->orig_file,0,-1); /* The original file */
-
- do
- {
- readlen = Read(fn->filehandle, buffer, 2048);
- RealWrite(fn->orig_file, buffer, readlen);
- }
- while (readlen == 2048);
- }
-
- /* Look for a powerpacker matchtag at the beginning of a file. Returns TRUE
- ** if the file was indeed a powerpacker datafile.
- */
- isppfile(register BPTR fh)
- {
- int ppmatchtag;
-
- /* This function leaves the file position ptr. at 0 for non-PP files */
- Read(fh,(char *)&ppmatchtag,sizeof(int));
-
- if (ppmatchtag == PP20)
- return(1);
- else
- {
- Seek(fh,0,-1);
- return(0);
- }
- }
-
- closedel(register BPTR tempfh,register char *filnambuf)
- {
- RealClose(tempfh);
- DeleteFile(filnambuf);
- }
-
- BPTR xNewOpen(register char *filename, register mode)
- {
- UBYTE *memgot;
- int filelen;
- register BPTR tempfh,origfile;
- register struct Task *thistask;
-
- origfile = tempfh = RealOpen(filename,mode);
-
- /* We only deal with a few of the incoming calls:
- **
- ** 1) Files which CAN in fact be opened
- ** 2) We can't do anything about new files
- ** 3) Equally, we don't care about CON: or NIL: file open requests
- ** 4) We don't care about non-crunched files
- */
-
- if
- (
- !tempfh ||
- mode == MODE_NEWFILE ||
- !reallyfile(tempfh) ||
- !isppfile(tempfh)
- )
- return(tempfh);
-
- /* Now, ask ppLoadData to bring in the file */
- if (!myPPLoadData(tempfh,&memgot,&filelen))
- {
- char filnambuf[MAXPATHLEN];
- register char *t, *m;
-
- /* Generate a name for the temporary file */
- t = filename;
- if (m = (char *)index(t,':')) t = m+1;
- while (m = (char *)index(t,'/')) t = m+1;
-
- strcpy(filnambuf,temppath);
- strcat(filnambuf,t);
- strcat(filnambuf,".tmp");
-
- /* We have to ensure that the name is unique on 'temppath' */
- while (tempfh = RealOpen(filnambuf,MODE_OLDFILE))
- {
- char *xtra = "?";
-
- /* Pad the name with random characters. This
- ** should do the trick
- */
- RealClose(tempfh);
- *xtra = 'A' + (rand() % 26);
- strcat(filnambuf,xtra);
- }
-
- /* Now, open the temporary file and flush data we loaded into
- ** this file.
- */
- if (tempfh = RealOpen(filnambuf,MODE_NEWFILE))
- {
- register short w_err = 0;
-
- /* Write the decrunched data to our new file. We
- ** do this by writing a bit, then freeing a bit,
- ** then writing the next bit -- and so forth.
- ** When the temporary path is in RAM:, this is
- ** a very good way to keep PP from using too much
- ** memory at a time. (Read .DOC file for further
- ** details)
- */
-
- /* Chop it up in 10k slices
- ** - and DON'T try to change that!
- */
- while (filelen > 10239 && !w_err)
- {
- w_err = (RealWrite(tempfh,(char *)memgot,10240) != 10240);
- FreeMem(memgot,10240);
- filelen -= 10240;
- memgot += 10240;
- }
-
- if (w_err)
- {
- closedel(tempfh,filnambuf);
- tempfh = origfile;
- goto quitout;
- }
-
- /* Do the final odd-length slice, if any */
- if (filelen)
- {
- w_err = (RealWrite(tempfh,(char *)memgot,filelen) != filelen);
- FreeMem(memgot,filelen);
-
- if (w_err)
- {
- closedel(tempfh,filnambuf);
- tempfh = origfile;
- goto quitout;
- }
- }
-
- /* We need to reopen the file in "MODE_OLDFILE" */
- RealClose(tempfh);
- tempfh = RealOpen(filnambuf,MODE_OLDFILE);
-
- /* Remember that WE created that file */
- if (!addfilenode(tempfh,filnambuf,origfile))
- {
- /* Couln't do it. Return original filehandle */
- closedel(tempfh,filnambuf);
- tempfh = origfile;
- }
- }
- else
- {
-
- /* Housekeeping */
- FreeMem(memgot,filelen);
-
- /* Return original file */
- tempfh = origfile;
- }
- }
-
- quitout:
-
- /* Return a filehandle to the file (ours or the original) */
- Seek(tempfh,0,-1);
- return(tempfh);
- }
-
- /* This is the new Open() functions. All future calls to the DOS Open()
- ** function will be rerouted through here.
- */
- BPTR NewOpen(register char *filename, register mode)
- {
- register BPTR retval;
-
- if (CheckOpen()) viruswarn("Open");
-
- if (pending_exit)
- return(RealOpen(filename,mode));
-
- opencnt++;
- retval = xNewOpen(filename,mode);
- opencnt--;
-
- return(retval);
- }
-
- int xNewWrite(register BPTR filehandle, register char *buffer, int length)
- {
- register struct filenode *fn;
- register wrtret;
-
- wrtret = RealWrite(filehandle, buffer, length);
-
- if (fn = findfilenode(filehandle))
- fn->dirty = 1;
-
- return(wrtret);
- }
-
- /* Yep! A new Write() function. We have to know if a process has updated
- ** the (substitute) file we created for it. If true, mark the file as
- ** being "dirty", so that we can later save it over the original PP file.
- */
- int NewWrite(register BPTR filehandle, register char *buffer, int length)
- {
- register retval;
-
- if (CheckWrite()) viruswarn("Write");
-
- if (pending_exit)
- return(RealWrite(filehandle,buffer,length));
-
- writecnt++;
- retval = xNewWrite(filehandle,buffer,length);
- writecnt--;
-
- return(retval);
- }
-
- void xNewClose(register BPTR filehandle)
- {
- register struct filenode *fn;
-
- if (fn = findfilenode(filehandle))
- {
- Forbid();
- Remove((struct Node *)fn);
- Permit();
-
- if (fn->dirty)
- flushout(fn);
-
- RealClose(fn->orig_file);
- RealClose(filehandle);
- DeleteFile(fn->new_filename);
-
- FreeMem(fn->new_filename,strlen(fn->new_filename)+1);
- FreeMem(fn,sizeof(*fn));
- }
- else
- RealClose(filehandle);
- }
-
- /* A new Close() function. It removes non-dirty, temporary files from
- ** 'temppath', and it keeps track of which files have to be updated back
- ** onto disk.
- */
- void NewClose(register BPTR filehandle)
- {
- if (CheckClose()) viruswarn("Close");
-
- if (pending_exit)
- RealClose(filehandle);
- else
- {
- closecnt++;
- xNewClose(filehandle);
- closecnt--;
- }
- }
-
- int xNewExamine(BPTR lock, struct FileInfoBlock *fib)
- {
- int decrunchinfo;
- register examinereturn;
- register BPTR tmpfh;
- struct FileInfoBlock fib_backup;
-
- /* Start off by examining the lock */
- if (!(examinereturn = RealExamine(lock,fib)))
- return(0);
-
- /* If it's a directory, never mind */
- if (fib->fib_DirEntryType >= 0)
- return(examinereturn);
-
- /* The lock target was a simple file. Check to see if it's a
- ** PP file
- */
- fib_backup = *fib;
- tmpfh = RealOpen(fullname(lock,fib),MODE_OLDFILE);
- *fib = fib_backup;
-
- if (!tmpfh)
- return(examinereturn);
-
- if (isppfile(tmpfh))
- {
- /* It was. Examine decrunchinfo to get at the original
- ** filesize, so that programs trying to allocate enough
- ** memory to hold a certain file will get the correct
- ** filesize (which is, of corz, size of the decrunched
- ** file!)
- */
- Seek(tmpfh,-4,1);
- Read(tmpfh,(char *)&decrunchinfo,sizeof(int));
- fib->fib_Size = decrunchinfo >> 8;
- }
-
- RealClose(tmpfh);
-
- return(examinereturn);
- }
-
- /* A new Examine() function. Often, programs examine a file before opening
- ** it. This way, they can allocate just enough memory to hold the entire
- ** file. However, we have to correct Examine() calls to PowerPacked files,
- ** so that the correct amount of memory will be allocated by the caller.
- */
- int NewExamine(BPTR lock, struct FileInfoBlock *fib)
- {
- register retval;
-
- if (CheckExamine()) viruswarn("Examine");
-
- if (pending_exit)
- return(RealExamine(lock,fib));
-
- examcnt++;
- retval = xNewExamine(lock,fib);
- examcnt--;
-
- return(retval);
- }
-
- maydie()
- {
- Forbid();
- pending_exit = !(templist.mlh_Head->mln_Succ)
- && !(opencnt | closecnt | examcnt | writecnt)
- && !(CheckOpen() | CheckClose() | CheckExamine() | CheckWrite());
- Permit();
-
- return(pending_exit);
- }
-
- /* Hangaround() waits for messages to arrive at our port, and then deals
- ** with them. This routine could be written in a much smaller version, but
- ** I've written it so that it will be easy to add more 'commands'.
- */
- int hangaround()
- {
- register MYMSG *m;
-
- pp_port->mp_SigTask = FindTask(0);
-
- FOREVER
- {
- WaitPort(pp_port);
-
- while (m = (MYMSG *)GetMsg(pp_port))
- {
- short candie;
-
- /* Eventually, some kind of actual communication
- ** will take place here. In this version, we simply
- ** quit whenever we spot an incoming message.
- */
-
- if (candie = maydie())
- m->Result = 1;
- else
- m->Result = 0;
-
- ReplyMsg((struct Message *)m);
-
- if (candie)
- {
- cleanup();
- return(0);
- }
- }
- }
- }
-
- /* Entry point */
- void main(int argc, char *argv[])
- {
- wbmode = (argc == 0);
-
- openstuff(argc,argv);
-
- if (!wbmode)
- {
- if (!res("Powerpacker Patcher",0,hangaround,4000))
- die(30,"Can't spawn background process!\n");
- else
- /* Tell the world the good news (CLI) */
- Say(gbanner);
- }
- else
- {
- /* Tell the world the good news (Workbench) */
- Say(gbanner);
-
- hangaround();
- }
- }
-